package emu.decvices.clock;

import emu.EMU;
import emu.decvices.apu.APU;
import emu.decvices.cpu.CPU;
import emu.decvices.ppu.PPU;

import java.io.Serializable;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

/**
 * 时钟
 */
public class Clock implements Serializable {

    private static final long NANOS_PER_SECOND = 1000000000;// 一秒钟有多少纳秒
    private static final long CPU_FREQUENCY_NTSC = 1789773; // NTSC的CPU频率，单位为赫兹(Hz)
    private static final long PPU_FREQUENCY = CPU_FREQUENCY_NTSC * 3;//PPU频率，单位为赫兹

    // 根据CPU频率计算每个CPU周期的纳秒数
//    private static final long NANOS_PER_CYCLE = NANOS_PER_SECOND / CPU_FREQUENCY_NTSC;
    private static final long NANOS_PER_CYCLE = NANOS_PER_SECOND / PPU_FREQUENCY;

    // 声明一个AtomicInteger类型的cycleCount变量，用来记录时钟周期数
    private AtomicInteger cycleCount = new AtomicInteger();
    private CPU cpu;
    private PPU ppu;

    private APU apu;

    //时钟是否运行
    private boolean running = false;
    private boolean ppu_dma_running = true;
    private boolean apu_dma_running = true;

    public Clock(CPU cpu, PPU ppu, APU apu) {
        this.cpu = cpu;
        this.ppu = ppu;
        this.apu = apu;
    }

    public void shutdown() {
        running = false;
    }

    public void start() {
        Thread t = new Thread(() -> {
            running = true; // 开启主循环
            long lastTime = System.nanoTime(); // 获取当前时间的纳秒值
            long accumulatedTime = 0L; // 初始化累计时间

            // 主循环
            while (running) {
                long currentTime = System.nanoTime(); // 获取当前时间
                long deltaTime = currentTime - lastTime; // 计算时间差
                lastTime = currentTime; // 更新上一次的时间
                accumulatedTime += deltaTime; // 更新累计时间

                // 如果累计时间大于或等于一个CPU周期，那么运行一次CPU时钟操作
                while (running && accumulatedTime >= NANOS_PER_CYCLE) {
                    onClock(cycleCount.getAndIncrement()); // 执行时钟操作并增加时钟周期数
                    accumulatedTime -= NANOS_PER_CYCLE; // 减去已模拟的 CPU 周期时间
                }

                // 计算需要暂停的时间
                long sleepTime = NANOS_PER_CYCLE - accumulatedTime;
                if (sleepTime > 0) {
                    // 如果需要暂停的时间大于0，那么暂停指定的时间
                    LockSupport.parkNanos(sleepTime);
                }
            }
            EMU.getInstance().onClockShutdown();
        });
        t.start();
    }

    public void onClock(int cycleCount) {
        ppu.clock();
//        if(cycleCount%6==0){
//            apu.clock();
//        }
        if (cycleCount % 3 == 0) {
//            if(apu.getDma().isTransfer(cycleCount)){
//                apu.getDma().transfer();
//            }else
            if (ppu.getDma().isTransfer(cycleCount)) {
                ppu.getDma().transfer();
            } else {
                cpu.clock();
            }

        }


        if (ppu.isNmi()) {
            ppu.setNmi(false);
            cpu.nmi();
        }

    }

}
